package cn.wygandwdn.core.transport.server;

import cn.wygandwdn.common.factory.SingletonFactory;
import cn.wygandwdn.common.utils.IpAddressUtil;
import cn.wygandwdn.core.codec.MessageCodec;
import cn.wygandwdn.core.codec.ProtocolFrameDecoder;
import cn.wygandwdn.core.config.Config;
import cn.wygandwdn.core.hook.ShutdownHook;
import cn.wygandwdn.core.registry.ServiceProvider;
import cn.wygandwdn.core.registry.ServiceRegistry;
import cn.wygandwdn.core.registry.impl.ServiceProviderImpl;
import cn.wygandwdn.core.spring.SpringBeanPostProcessor;
import cn.wygandwdn.core.transport.server.handler.HeartBeatServerHandler;
import cn.wygandwdn.core.transport.server.handler.RpcServerHandler;
import cn.wygandwdn.core.transport.server.handler.RpcServerPingHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.net.UnknownHostException;
import java.util.concurrent.TimeUnit;


/**
 * @description:
 * @author: WYG
 * @time: 2021/10/27 16:05
 */

public class RpcServer {
    private static final Logger log = LoggerFactory.getLogger(RpcServer.class);

    private final ServiceProvider provider;
    private final ServiceRegistry registry;
    private String host;
    private int port;

    public RpcServer(Class<?> cls) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(cls);
        this.provider = SingletonFactory.getInstance(ServiceProviderImpl.class);
        this.registry = Config.getRegistry();
        try {
            this.host = IpAddressUtil.getHost();
        } catch (UnknownHostException e) {
            log.error("get host error: {}", e);
        }
        this.port = Config.getServerPort();
    }

    public void start() {
        ShutdownHook.getShutdownHook().addClearHook(host, port);
        EventLoopGroup boss = new NioEventLoopGroup();
        EventLoopGroup worker = new NioEventLoopGroup();
        ServerBootstrap server = new ServerBootstrap();
        MessageCodec CODEC = new MessageCodec();
        HeartBeatServerHandler HEART = new HeartBeatServerHandler();
        RpcServerPingHandler PING = new RpcServerPingHandler();
        RpcServerHandler HANDLER = new RpcServerHandler();
        try {
            server.group(boss, worker)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<NioSocketChannel>() {
                        @Override
                        protected void initChannel(NioSocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast(new ProtocolFrameDecoder());
                            pipeline.addLast(CODEC);
                            pipeline.addLast(new IdleStateHandler(6, 0, 0, TimeUnit.SECONDS));
                            pipeline.addLast(HEART);
                            pipeline.addLast(PING);
                            pipeline.addLast(HANDLER);
                        }
                    });
            ChannelFuture future = server.bind(host, port).sync();
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            log.error("服务端发生异常: {}", e);
        } finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }

}
